﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Speech.Recognition;
using System.Text;
using System.Threading.Tasks;

namespace Windows_AI_Assistant.Helpers
{
    public class AudioHelper
    {
        private readonly string _tempFolderPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Temp");

        public AudioHelper()
        {
            // 定义要检查或创建的文件夹路径
            string folderPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Temp");

            // 检查文件夹是否存在
            if (!Directory.Exists(folderPath))
            {
                // 文件夹不存在，创建文件夹
                Directory.CreateDirectory(folderPath);
            }
        }

        /// <summary>
        /// 将音频流保存为文件
        /// </summary>
        /// <param name="recognizedAudio"></param>
        /// <param name="fileName"></param>
        public string SaveRecognizedAudioToFile(RecognizedAudio recognizedAudio, string fileName)
        {
            string filePath = System.IO.Path.Combine(_tempFolderPath, fileName);
            // 创建一个文件流，用于写入WAV文件
            using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
            {
                // 使用WriteToAudioStream方法将音频数据写入到文件流中
                recognizedAudio.WriteToAudioStream(fileStream);
                // 假设音频是16位PCM编码，单声道
                int bitsPerSample = 16; // 16位每样本
                int bytesPerSample = bitsPerSample / 8; // 16位每样本需要2字节
                int sampleRate = 16000; // 采样率16000Hz
                int channels = 1; // 单声道
                // 计算音频数据的大小（以字节为单位）
                long dataLength = (long)(recognizedAudio.Duration.TotalSeconds * sampleRate * bytesPerSample * channels);

                // 需要手动写入WAV文件头
                WriteWavHeader2(fileStream, dataLength, sampleRate, bitsPerSample, channels);
            }
            return filePath;
        }

        /// <summary>
        /// 将音频流写入WAV文件头
        /// </summary>
        /// <param name="stream">音频流</param>
        /// <param name="dataLength">文件流的大小（以字节为单位）</param>
        /// <param name="sampleRate">采样率</param>
        /// <param name="bitsPerSample">采样位数</param>
        /// <param name="channels">声道数</param>
        private void WriteWavHeader(Stream stream, long dataLength, int sampleRate, int bitsPerSample, int channels)
        {
            using (BinaryWriter binaryWriter = new BinaryWriter(stream, System.Text.Encoding.UTF8, true))
            {
                // Set the position to the beginning of the stream.
                stream.Position = 0;

                // The RIFF chunk descriptor
                binaryWriter.Write("RIFF".ToCharArray()); // ChunkID
                binaryWriter.Write((int)(36 + dataLength)); // ChunkSize
                binaryWriter.Write("WAVE".ToCharArray()); // Format

                // The fmt sub-chunk
                binaryWriter.Write("fmt ".ToCharArray()); // Subchunk1ID
                binaryWriter.Write(16); // Subchunk1Size
                binaryWriter.Write((ushort)1); // AudioFormat (PCM)
                binaryWriter.Write((ushort)channels); // NumChannels
                binaryWriter.Write(sampleRate); // SampleRate
                binaryWriter.Write(sampleRate * channels * bitsPerSample / 8); // ByteRate
                binaryWriter.Write((ushort)(channels * bitsPerSample / 8)); // BlockAlign
                binaryWriter.Write((ushort)bitsPerSample); // BitsPerSample

                // The data sub-chunk
                binaryWriter.Write("data".ToCharArray()); // Subchunk2ID
                binaryWriter.Write((int)dataLength); // Subchunk2Size

                // Set the position to the end of the header.
                stream.Position = 44;
            }
        }

        private void WriteWavHeader2(Stream stream, long dataLength, int sampleRate, int bitsPerSample, int channels)
        {
            using (BinaryWriter binaryWriter = new BinaryWriter(stream, System.Text.Encoding.UTF8, true))
            {
                // Set the position to the beginning of the stream.
                stream.Position = 0;

                // The RIFF chunk descriptor
                binaryWriter.Write(Encoding.ASCII.GetBytes("RIFF")); // ChunkID
                binaryWriter.Write((int)(36 + dataLength)); // ChunkSize
                binaryWriter.Write(Encoding.ASCII.GetBytes("WAVE")); // Format

                // The fmt sub-chunk
                binaryWriter.Write(Encoding.ASCII.GetBytes("fmt ")); // Subchunk1ID
                binaryWriter.Write(16); // Subchunk1Size
                binaryWriter.Write((ushort)1); // AudioFormat (PCM)
                binaryWriter.Write((ushort)channels); // NumChannels
                binaryWriter.Write(sampleRate); // SampleRate
                binaryWriter.Write(sampleRate * channels * bitsPerSample / 8); // ByteRate
                binaryWriter.Write((ushort)(channels * bitsPerSample / 8)); // BlockAlign
                binaryWriter.Write((ushort)bitsPerSample); // BitsPerSample

                // The data sub-chunk
                binaryWriter.Write(Encoding.ASCII.GetBytes("data")); // Subchunk2ID
                binaryWriter.Write((int)dataLength); // Subchunk2Size

                // Set the position to the end of the header.
                stream.Position = 44;
            }
        }

        /// <summary>
        /// 异步录制音频
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public async Task<string> RecordAudioAsync(string fileName)
        {
            string filePath = System.IO.Path.Combine(_tempFolderPath, fileName);

            // 使用 NAudio 录制音频
            using var waveIn = new NAudio.Wave.WaveInEvent();
            waveIn.WaveFormat = new NAudio.Wave.WaveFormat(16000, 1);
            var writer = new NAudio.Wave.WaveFileWriter(filePath, waveIn.WaveFormat);

            waveIn.DataAvailable += (s, e) => writer.Write(e.Buffer, 0, e.BytesRecorded);
            waveIn.StartRecording();

            await Task.Delay(5000); // 录音 5 秒
            waveIn.StopRecording();
            writer.Dispose();

            return filePath;
        }
    }
}
